Das Ziel ist es, aus dem Datacamp Datensatz Soccer Data, welcher Daten aus der höchsten englischen Fussballdivision beinhaltet, folgende Fragestellung / Hypothese zu beantworten:

Die Manschaft, die zur Halbzeit vorne liegt, gewinnt mit einer Chance von mindestens 75% das Spiel. Falls zur Halbzeit unentschieden ist, gewinnt eher das Heimteam mit einer Chance von mindestens 33.4%.

Als Einführung werden wir auf Datacamp folgende Kurse durchgehen:

# Import libraries
library("plotly")
library("plyr")
library("dplyr")
library("forcats")
library("RColorBrewer")

Daten einlesen und Dataframe erstellen

# List files in folder "data"
files <- list.files(path="./data/", pattern=NULL, all.files=FALSE, full.names=TRUE)

# Create Dataframe with all csv from years 2015-2019
df <- ldply(.data = files, .fun = read.csv)

View(df)

Hier zählen wir, wie oft das Heim - und Auswärtsteam zur Halb - und Vollzeit gewinnen oder ob das Spiel unentschieden ist.

# Create dataframe for halftime & fulltime results and count frequency 
df_htr <- df %>% count(HTR)
df_ftr <- df %>% count(FTR)

# Halftime
df_htr
# Fulltime
df_ftr
# Create dataframe with halftime & fulltime result frequency
df_results <- data.frame(c("Away win", "Draw", "Home win"), c(df_htr$n), c(df_ftr$n))

# Rename column headers
col_headings <- c('Result','Halftime','Fulltime')
names(df_results) <- col_headings

df_results
# Plot grouped bar chart to visualize halftime & fulltime results
fig <- plot_ly(
  df_results, x = ~Result, y = ~Halftime, type = 'bar', name = 'Halftime Score') %>% 
  add_trace(y = ~Fulltime, name = 'Fulltime Score') %>%
  layout(yaxis = list(title = 'Amount'), 
         barmode = 'group',
         width = 600, height = 500)
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
fig
# Merge HTR & FTR to new column 'result'
df$result <- paste(df$HTR, df$FTR)

# Example: H H = home team is winning at halftime and also wins the game at fulltime

df[,"result", drop=FALSE]
# Plot all different game progresses and their amount
df_count_results <- df %>%
  count(result)
  
df_count_results %>%
  mutate(result = fct_reorder(result, n, .desc = TRUE)) %>%
  plot_ly(x = ~result, y = ~n, text = ~n, textposition = 'auto') %>%
  add_bars() %>%
  layout(xaxis = list(title = "Game Progress"),
         yaxis = list(title = "Amount of Game Progresses"),
         title = "How are the different game progresses distributed?",
         width = 800, height = 500)
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()

Hier wollen wir herausfinden, wie wahrscheinlich die 9 möglichen Spielausgängen sind bevor das Spiel überhaupt beginnt.

# Group by game outcome & calculate probability of all outcomes
df_count_results_prob <- df %>% 
  group_by(result) %>% 
  summarise(count_result = round(n() / nrow(df) * 100, digits = 2))

# Plot all different game progresses and their probability
df_count_results_prob %>%
  mutate(result = fct_reorder(result, count_result, .desc = TRUE)) %>%
  plot_ly(x = ~result, y = ~count_result, text = ~count_result, textposition = 'auto') %>%
  add_bars() %>%
  layout(xaxis = list(title = "Game Progress"),
         yaxis = list(title = "Probability of Game Progress (%)"),
         title = "How are the different game progresses distributed?",
         width = 800, height = 500)
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
# Group by game outcome & calculate probability of all outcomes
df_count_results <- df %>% 
  group_by(result) %>% 
  summarise(count_result = round(n() / nrow(df) * 100, digits = 2))

df_count_results %>%
  plot_ly(labels = ~result, values = ~count_result) %>%
  add_pie(hole = 0.4, color = I("white")) %>%
  layout(xaxis = list(title = "Game Progress"),
         yaxis = list(title = "Probability %"),
         title = "What is the probability of each game progress?")
# Calculate probability between halftime & fulltime away / draw / home results
calc_prob <- function(df1, df2) {
  prob <- round((100 / nrow(df1) * nrow(df2)), digits = 2)
  return(prob)
}
# Filter home teams winning at halftime
df_ht_home <- df %>% 
  filter(HTR == "H")

# Filter home teams winning at halftime & fulltime
df_ft_home <- df_ht_home %>% 
  filter(FTR == "H")

home_win_prob <- calc_prob(df_ht_home, df_ft_home)

cat("Probability that the home team wins the game if they are leading at half time: ", home_win_prob, "%")
Probability that the home team wins the game if they are leading at half time:  82.55 %
# Filter away teams winning at halftime
df_ht_away <- df %>% 
  filter(HTR == "A")

# Filter away teams winning at halftime & fulltime
df_ft_away <- df_ht_away %>% 
  filter(FTR == "A")

away_win_prob <- calc_prob(df_ht_away, df_ft_away)

cat("Probability that the away team wins the game if they are leading at half time: ", away_win_prob, "%")
Probability that the away team wins the game if they are leading at half time:  72.03 %
# Filter draw at halftime
df_ht_draw <- df %>% 
  filter(HTR == "D")

# Filter draw at halftime & fulltime
df_ft_draw <- df_ht_draw %>% 
  filter(FTR == "D")

draw_prob <- calc_prob(df_ht_draw, df_ft_draw)

cat("Probability that the game ends in a draw if the halftime result is also a draw: ", draw_prob, "%")
Probability that the game ends in a draw if the halftime result is also a draw:  36.45 %
# Filter draw at halftime & the home team winning at fulltime
df_ht_draw_ft_home_win <- df_ht_draw %>%
  filter(FTR == "H")

home_win_after_ht_draw_prob <- calc_prob(df_ht_draw, df_ht_draw_ft_home_win)

cat("Probability that the home team wins if the halftime result is a draw: ", home_win_after_ht_draw_prob, "%")
Probability that the home team wins if the halftime result is a draw:  38.03 %

Bestätigung der Hypothese

Somit können wir aus die 2 Wahrscheinlichkeiten “home_win_prob” und “away_win_prob” unsere Hypothese wie folgt bestätigen:

# Probability that the team winning at half time wins the game
ht_ft_win_prob <- round(((home_win_prob * nrow(df_ft_home)) + (away_win_prob * nrow(df_ft_away))) / (nrow(df_ft_home) + nrow(df_ft_away)), digits = 2)

cat("Probability that the team leading at half time wins the entire game: ", ht_ft_win_prob, "%")
Probability that the team leading at half time wins the entire game:  78.41 %
fig <- plot_ly(
  y = c("Home wins after leading at HT", "Away wins after leading at HT", "Draw at FT & HT"), 
  x = c(home_win_prob, away_win_prob, draw_prob),
  type = "bar"
)

fig <- fig %>% layout(title = "Game Progress Overview",
         xaxis = list(title = "Probability"))

fig
NA

Fragestellung 2:

Das Heimteam schiesst mehr aufs Tor als das Auswärtsteam, aber welches Team ist effizienter?

# Plot Fulltime Home Shots vs Home Goals 
p1 <- df %>%
  plot_ly(x = ~FTHG, y = ~HS, coloraxis = 'coloraxis') %>%
  add_histogram2d(nbinsy = 40)

# Plot Fulltime Away Shots vs Away Goals 
p2 <- df %>%
  plot_ly(x = ~FTAG, y = ~AS, coloraxis = 'coloraxis') %>%
  add_histogram2d(nbinsy = 40)

# Add both plots together to build subplot
subplot(p1, p2, nrows = 1, shareX = FALSE, shareY = FALSE) %>%
  layout(
    title = "Goals vs Shots Overview",
    xaxis = list(title = "Home Goals"),
    xaxis2 = list(title = "Away Goals"),
    yaxis = list(title = "Home Shots"),
    yaxis2 = list(title = "Away Shots"),
    coloraxis=list(colorscale='Jet')
  )

Anhand des Plots oben ist gut zu sehen, dass das Heimteam eher 1-2 Tore schiesst und 9-16 Torschüsse aufweist. Beim Auswärtsteam siehts etwas anders aus; Sie schiessen eher 0-1 Tor und weisen 6-11 Torschüsse auf.

# Fit the regression model of Fulltime Away Goals on Away Shots
m <- lm(FTAG ~ AS, data = df)

# Create the scatterplot with smoother
df %>%
  plot_ly(x = ~AS, y = ~FTAG) %>%
  add_markers(showlegend = FALSE) %>%
  add_lines(y = ~fitted(m))
df %>%
  plot_ly(x = ~HS, y = ~AS, coloraxis = 'coloraxis') %>%
  add_histogram2d(nbinsx = 70, nbinsy = 60) %>%
  layout(coloraxis=list(colorscale='Jet'))
df_efficiency <- df %>%
  summarise(
    "Home Goals per Shot" = round(sum(FTHG) / sum(HS),digits = 3),
    "Home Goals per Shot on Target" = round(sum(FTHG) / sum(HST),digits = 3),
    "Away Goals per Shot" = round(sum(FTAG) / sum(AS),digits = 3),
    "Away Goals per Shot on Target" = round(sum(FTAG) / sum(AST),digits = 3)
)
# Transpose dataframe
t_df_efficiency <- data.frame("Percent" = t(df_efficiency))
fig <- plot_ly(
  y = c("Home Goals per Shot", "Home Goals per Shot on Target", "Away Goals per Shot", "Away Goals per Shot on Target"),
  x = t_df_efficiency$Percent,
  type = "bar"
)

fig <- fig %>% layout(title = "Team Efficiency",
         xaxis = list(title = "Probability"))

fig
LS0tDQp0aXRsZTogIkRhdGEgVmlzdWFsaXphdGlvbiBtaXQgUGxvdGx5Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KRGFzIFppZWwgaXN0IGVzLCBhdXMgZGVtIERhdGFjYW1wIERhdGVuc2F0eiBbU29jY2VyIERhdGFdKGh0dHBzOi8vYXBwLmRhdGFjYW1wLmNvbS93b3Jrc3BhY2UvZGF0YXNldHMvZGF0YXNldC1weXRob24tc29jY2VyKSwgd2VsY2hlciBEYXRlbiBhdXMgZGVyIGjDtmNoc3RlbiBlbmdsaXNjaGVuIEZ1c3NiYWxsZGl2aXNpb24gYmVpbmhhbHRldCwgZm9sZ2VuZGUgRnJhZ2VzdGVsbHVuZyAvIEh5cG90aGVzZSB6dSBiZWFudHdvcnRlbjoNCg0KDQojIyMgRGllIE1hbnNjaGFmdCwgZGllIHp1ciBIYWxiemVpdCB2b3JuZSBsaWVndCwgZ2V3aW5udCBtaXQgZWluZXIgQ2hhbmNlIHZvbiBtaW5kZXN0ZW5zIDc1JSBkYXMgU3BpZWwuIEZhbGxzIHp1ciBIYWxiemVpdCB1bmVudHNjaGllZGVuIGlzdCwgZ2V3aW5udCBlaGVyIGRhcyBIZWltdGVhbSBtaXQgZWluZXIgQ2hhbmNlIHZvbiBtaW5kZXN0ZW5zIDMzLjQlLg0KDQoNCkFscyBFaW5mw7xocnVuZyB3ZXJkZW4gd2lyIGF1ZiBEYXRhY2FtcCBmb2xnZW5kZSBLdXJzZSBkdXJjaGdlaGVuOg0KDQotIFtJbnRlcmFjdGl2ZSBEYXRhIFZpc3VhbGl6YXRpb24gd2l0aCBwbG90bHldKGh0dHBzOi8vYXBwLmRhdGFjYW1wLmNvbS9sZWFybi9jb3Vyc2VzL2ludGVyYWN0aXZlLWRhdGEtdmlzdWFsaXphdGlvbi13aXRoLXBsb3RseS1pbi1yKQ0KDQotIFtJbnRlcm1lZGlhdGUgSW50ZXJhY3RpdmUgRGF0YSBWaXN1YWxpemF0aW9uIHdpdGggcGxvdGx5XShodHRwczovL2FwcC5kYXRhY2FtcC5jb20vbGVhcm4vY291cnNlcy9pbnRlcmFjdGl2ZS1kYXRhLXZpc3VhbGl6YXRpb24td2l0aC1wbG90bHktaW4tcikNCg0KDQpgYGB7cn0NCiMgSW1wb3J0IGxpYnJhcmllcw0KbGlicmFyeSgicGxvdGx5IikNCmxpYnJhcnkoInBseXIiKQ0KbGlicmFyeSgiZHBseXIiKQ0KbGlicmFyeSgiZm9yY2F0cyIpDQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQ0KYGBgDQoNCiMjIyBEYXRlbiBlaW5sZXNlbiB1bmQgRGF0YWZyYW1lIGVyc3RlbGxlbg0KDQpgYGB7cn0NCiMgTGlzdCBmaWxlcyBpbiBmb2xkZXIgImRhdGEiDQpmaWxlcyA8LSBsaXN0LmZpbGVzKHBhdGg9Ii4vZGF0YS8iLCBwYXR0ZXJuPU5VTEwsIGFsbC5maWxlcz1GQUxTRSwgZnVsbC5uYW1lcz1UUlVFKQ0KDQojIENyZWF0ZSBEYXRhZnJhbWUgd2l0aCBhbGwgY3N2IGZyb20geWVhcnMgMjAxNS0yMDE5DQpkZiA8LSBsZHBseSguZGF0YSA9IGZpbGVzLCAuZnVuID0gcmVhZC5jc3YpDQoNClZpZXcoZGYpDQpgYGANCg0KSGllciB6w6RobGVuIHdpciwgd2llIG9mdCBkYXMgSGVpbSAtIHVuZCBBdXN3w6RydHN0ZWFtIHp1ciBIYWxiIC0gdW5kIFZvbGx6ZWl0IGdld2lubmVuIG9kZXIgb2IgZGFzIFNwaWVsIHVuZW50c2NoaWVkZW4gaXN0Lg0KDQotIEEgPSBBdXN3w6RydHN0ZWFtIGdld2lubnQNCg0KLSBEID0gVW5lbnRzY2hpZWRlbg0KDQotIEggPSBIZWltdGVhbSBnZXdpbm50DQoNCmBgYHtyfQ0KIyBDcmVhdGUgZGF0YWZyYW1lIGZvciBoYWxmdGltZSAmIGZ1bGx0aW1lIHJlc3VsdHMgYW5kIGNvdW50IGZyZXF1ZW5jeSANCmRmX2h0ciA8LSBkZiAlPiUgY291bnQoSFRSKQ0KZGZfZnRyIDwtIGRmICU+JSBjb3VudChGVFIpDQoNCiMgSGFsZnRpbWUNCmRmX2h0cg0KIyBGdWxsdGltZQ0KZGZfZnRyDQpgYGANCg0KYGBge3J9DQojIENyZWF0ZSBkYXRhZnJhbWUgd2l0aCBoYWxmdGltZSAmIGZ1bGx0aW1lIHJlc3VsdCBmcmVxdWVuY3kNCmRmX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZShjKCJBd2F5IHdpbiIsICJEcmF3IiwgIkhvbWUgd2luIiksIGMoZGZfaHRyJG4pLCBjKGRmX2Z0ciRuKSkNCg0KIyBSZW5hbWUgY29sdW1uIGhlYWRlcnMNCmNvbF9oZWFkaW5ncyA8LSBjKCdSZXN1bHQnLCdIYWxmdGltZScsJ0Z1bGx0aW1lJykNCm5hbWVzKGRmX3Jlc3VsdHMpIDwtIGNvbF9oZWFkaW5ncw0KDQpkZl9yZXN1bHRzDQpgYGANCmBgYHtyfQ0KIyBQbG90IGdyb3VwZWQgYmFyIGNoYXJ0IHRvIHZpc3VhbGl6ZSBoYWxmdGltZSAmIGZ1bGx0aW1lIHJlc3VsdHMNCmZpZyA8LSBwbG90X2x5KA0KICBkZl9yZXN1bHRzLCB4ID0gflJlc3VsdCwgeSA9IH5IYWxmdGltZSwgdHlwZSA9ICdiYXInLCBuYW1lID0gJ0hhbGZ0aW1lIFNjb3JlJykgJT4lIA0KICBhZGRfdHJhY2UoeSA9IH5GdWxsdGltZSwgbmFtZSA9ICdGdWxsdGltZSBTY29yZScpICU+JQ0KICBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0Ftb3VudCcpLCANCiAgICAgICAgIGJhcm1vZGUgPSAnZ3JvdXAnLA0KICAgICAgICAgd2lkdGggPSA2MDAsIGhlaWdodCA9IDUwMCkNCg0KZmlnDQpgYGANCg0KDQpgYGB7cn0NCiMgTWVyZ2UgSFRSICYgRlRSIHRvIG5ldyBjb2x1bW4gJ3Jlc3VsdCcNCmRmJHJlc3VsdCA8LSBwYXN0ZShkZiRIVFIsIGRmJEZUUikNCg0KIyBFeGFtcGxlOiBIIEggPSBob21lIHRlYW0gaXMgd2lubmluZyBhdCBoYWxmdGltZSBhbmQgYWxzbyB3aW5zIHRoZSBnYW1lIGF0IGZ1bGx0aW1lDQoNCmRmWywicmVzdWx0IiwgZHJvcD1GQUxTRV0NCmBgYA0KDQpgYGB7cn0NCiMgUGxvdCBhbGwgZGlmZmVyZW50IGdhbWUgcHJvZ3Jlc3NlcyBhbmQgdGhlaXIgYW1vdW50DQpkZl9jb3VudF9yZXN1bHRzIDwtIGRmICU+JQ0KICBjb3VudChyZXN1bHQpDQogIA0KZGZfY291bnRfcmVzdWx0cyAlPiUNCiAgbXV0YXRlKHJlc3VsdCA9IGZjdF9yZW9yZGVyKHJlc3VsdCwgbiwgLmRlc2MgPSBUUlVFKSkgJT4lDQogIHBsb3RfbHkoeCA9IH5yZXN1bHQsIHkgPSB+biwgdGV4dCA9IH5uLCB0ZXh0cG9zaXRpb24gPSAnYXV0bycpICU+JQ0KICBhZGRfYmFycygpICU+JQ0KICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIkdhbWUgUHJvZ3Jlc3MiKSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJBbW91bnQgb2YgR2FtZSBQcm9ncmVzc2VzIiksDQogICAgICAgICB0aXRsZSA9ICJIb3cgYXJlIHRoZSBkaWZmZXJlbnQgZ2FtZSBwcm9ncmVzc2VzIGRpc3RyaWJ1dGVkPyIsDQogICAgICAgICB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNTAwKQ0KYGBgDQoNCkhpZXIgd29sbGVuIHdpciBoZXJhdXNmaW5kZW4sIHdpZSB3YWhyc2NoZWlubGljaCBkaWUgOSBtw7ZnbGljaGVuIFNwaWVsYXVzZ8OkbmdlbiBzaW5kIGJldm9yIGRhcyBTcGllbCDDvGJlcmhhdXB0IGJlZ2lubnQuDQoNCmBgYHtyfQ0KIyBHcm91cCBieSBnYW1lIG91dGNvbWUgJiBjYWxjdWxhdGUgcHJvYmFiaWxpdHkgb2YgYWxsIG91dGNvbWVzDQpkZl9jb3VudF9yZXN1bHRzX3Byb2IgPC0gZGYgJT4lIA0KICBncm91cF9ieShyZXN1bHQpICU+JSANCiAgc3VtbWFyaXNlKGNvdW50X3Jlc3VsdCA9IHJvdW5kKG4oKSAvIG5yb3coZGYpICogMTAwLCBkaWdpdHMgPSAyKSkNCg0KIyBQbG90IGFsbCBkaWZmZXJlbnQgZ2FtZSBwcm9ncmVzc2VzIGFuZCB0aGVpciBwcm9iYWJpbGl0eQ0KZGZfY291bnRfcmVzdWx0c19wcm9iICU+JQ0KICBtdXRhdGUocmVzdWx0ID0gZmN0X3Jlb3JkZXIocmVzdWx0LCBjb3VudF9yZXN1bHQsIC5kZXNjID0gVFJVRSkpICU+JQ0KICBwbG90X2x5KHggPSB+cmVzdWx0LCB5ID0gfmNvdW50X3Jlc3VsdCwgdGV4dCA9IH5jb3VudF9yZXN1bHQsIHRleHRwb3NpdGlvbiA9ICdhdXRvJykgJT4lDQogIGFkZF9iYXJzKCkgJT4lDQogIGxheW91dCh4YXhpcyA9IGxpc3QodGl0bGUgPSAiR2FtZSBQcm9ncmVzcyIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5IG9mIEdhbWUgUHJvZ3Jlc3MgKCUpIiksDQogICAgICAgICB0aXRsZSA9ICJIb3cgYXJlIHRoZSBkaWZmZXJlbnQgZ2FtZSBwcm9ncmVzc2VzIGRpc3RyaWJ1dGVkPyIsDQogICAgICAgICB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNTAwKQ0KYGBgDQoNCmBgYHtyfQ0KIyBHcm91cCBieSBnYW1lIG91dGNvbWUgJiBjYWxjdWxhdGUgcHJvYmFiaWxpdHkgb2YgYWxsIG91dGNvbWVzDQpkZl9jb3VudF9yZXN1bHRzIDwtIGRmICU+JSANCiAgZ3JvdXBfYnkocmVzdWx0KSAlPiUgDQogIHN1bW1hcmlzZShjb3VudF9yZXN1bHQgPSByb3VuZChuKCkgLyBucm93KGRmKSAqIDEwMCwgZGlnaXRzID0gMikpDQoNCmRmX2NvdW50X3Jlc3VsdHMgJT4lDQogIHBsb3RfbHkobGFiZWxzID0gfnJlc3VsdCwgdmFsdWVzID0gfmNvdW50X3Jlc3VsdCkgJT4lDQogIGFkZF9waWUoaG9sZSA9IDAuNCwgY29sb3IgPSBJKCJ3aGl0ZSIpKSAlPiUNCiAgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJHYW1lIFByb2dyZXNzIiksDQogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUHJvYmFiaWxpdHkgJSIpLA0KICAgICAgICAgdGl0bGUgPSAiV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgZWFjaCBnYW1lIHByb2dyZXNzPyIpDQpgYGANCmBgYHtyfQ0KIyBDYWxjdWxhdGUgcHJvYmFiaWxpdHkgYmV0d2VlbiBoYWxmdGltZSAmIGZ1bGx0aW1lIGF3YXkgLyBkcmF3IC8gaG9tZSByZXN1bHRzDQpjYWxjX3Byb2IgPC0gZnVuY3Rpb24oZGYxLCBkZjIpIHsNCiAgcHJvYiA8LSByb3VuZCgoMTAwIC8gbnJvdyhkZjEpICogbnJvdyhkZjIpKSwgZGlnaXRzID0gMikNCiAgcmV0dXJuKHByb2IpDQp9DQpgYGANCg0KYGBge3J9DQojIEZpbHRlciBob21lIHRlYW1zIHdpbm5pbmcgYXQgaGFsZnRpbWUNCmRmX2h0X2hvbWUgPC0gZGYgJT4lIA0KICBmaWx0ZXIoSFRSID09ICJIIikNCg0KIyBGaWx0ZXIgaG9tZSB0ZWFtcyB3aW5uaW5nIGF0IGhhbGZ0aW1lICYgZnVsbHRpbWUNCmRmX2Z0X2hvbWUgPC0gZGZfaHRfaG9tZSAlPiUgDQogIGZpbHRlcihGVFIgPT0gIkgiKQ0KDQpob21lX3dpbl9wcm9iIDwtIGNhbGNfcHJvYihkZl9odF9ob21lLCBkZl9mdF9ob21lKQ0KDQpjYXQoIlByb2JhYmlsaXR5IHRoYXQgdGhlIGhvbWUgdGVhbSB3aW5zIHRoZSBnYW1lIGlmIHRoZXkgYXJlIGxlYWRpbmcgYXQgaGFsZiB0aW1lOiAiLCBob21lX3dpbl9wcm9iLCAiJSIpDQpgYGANCmBgYHtyfQ0KIyBGaWx0ZXIgYXdheSB0ZWFtcyB3aW5uaW5nIGF0IGhhbGZ0aW1lDQpkZl9odF9hd2F5IDwtIGRmICU+JSANCiAgZmlsdGVyKEhUUiA9PSAiQSIpDQoNCiMgRmlsdGVyIGF3YXkgdGVhbXMgd2lubmluZyBhdCBoYWxmdGltZSAmIGZ1bGx0aW1lDQpkZl9mdF9hd2F5IDwtIGRmX2h0X2F3YXkgJT4lIA0KICBmaWx0ZXIoRlRSID09ICJBIikNCg0KYXdheV93aW5fcHJvYiA8LSBjYWxjX3Byb2IoZGZfaHRfYXdheSwgZGZfZnRfYXdheSkNCg0KY2F0KCJQcm9iYWJpbGl0eSB0aGF0IHRoZSBhd2F5IHRlYW0gd2lucyB0aGUgZ2FtZSBpZiB0aGV5IGFyZSBsZWFkaW5nIGF0IGhhbGYgdGltZTogIiwgYXdheV93aW5fcHJvYiwgIiUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBGaWx0ZXIgZHJhdyBhdCBoYWxmdGltZQ0KZGZfaHRfZHJhdyA8LSBkZiAlPiUgDQogIGZpbHRlcihIVFIgPT0gIkQiKQ0KDQojIEZpbHRlciBkcmF3IGF0IGhhbGZ0aW1lICYgZnVsbHRpbWUNCmRmX2Z0X2RyYXcgPC0gZGZfaHRfZHJhdyAlPiUgDQogIGZpbHRlcihGVFIgPT0gIkQiKQ0KDQpkcmF3X3Byb2IgPC0gY2FsY19wcm9iKGRmX2h0X2RyYXcsIGRmX2Z0X2RyYXcpDQoNCmNhdCgiUHJvYmFiaWxpdHkgdGhhdCB0aGUgZ2FtZSBlbmRzIGluIGEgZHJhdyBpZiB0aGUgaGFsZnRpbWUgcmVzdWx0IGlzIGFsc28gYSBkcmF3OiAiLCBkcmF3X3Byb2IsICIlIikNCmBgYA0KDQpgYGB7cn0NCiMgRmlsdGVyIGRyYXcgYXQgaGFsZnRpbWUgJiB0aGUgaG9tZSB0ZWFtIHdpbm5pbmcgYXQgZnVsbHRpbWUNCmRmX2h0X2RyYXdfZnRfaG9tZV93aW4gPC0gZGZfaHRfZHJhdyAlPiUNCiAgZmlsdGVyKEZUUiA9PSAiSCIpDQoNCmhvbWVfd2luX2FmdGVyX2h0X2RyYXdfcHJvYiA8LSBjYWxjX3Byb2IoZGZfaHRfZHJhdywgZGZfaHRfZHJhd19mdF9ob21lX3dpbikNCg0KY2F0KCJQcm9iYWJpbGl0eSB0aGF0IHRoZSBob21lIHRlYW0gd2lucyBpZiB0aGUgaGFsZnRpbWUgcmVzdWx0IGlzIGEgZHJhdzogIiwgaG9tZV93aW5fYWZ0ZXJfaHRfZHJhd19wcm9iLCAiJSIpDQpgYGANCiMjIyBCZXN0w6R0aWd1bmcgZGVyIEh5cG90aGVzZQ0KDQpTb21pdCBrw7ZubmVuIHdpciBhdXMgZGllIDIgV2FocnNjaGVpbmxpY2hrZWl0ZW4gImhvbWVfd2luX3Byb2IiIHVuZCAiYXdheV93aW5fcHJvYiIgdW5zZXJlIEh5cG90aGVzZSB3aWUgZm9sZ3QgYmVzdMOkdGlnZW46IA0KDQpgYGB7cn0NCiMgUHJvYmFiaWxpdHkgdGhhdCB0aGUgdGVhbSB3aW5uaW5nIGF0IGhhbGYgdGltZSB3aW5zIHRoZSBnYW1lDQpodF9mdF93aW5fcHJvYiA8LSByb3VuZCgoKGhvbWVfd2luX3Byb2IgKiBucm93KGRmX2Z0X2hvbWUpKSArIChhd2F5X3dpbl9wcm9iICogbnJvdyhkZl9mdF9hd2F5KSkpIC8gKG5yb3coZGZfZnRfaG9tZSkgKyBucm93KGRmX2Z0X2F3YXkpKSwgZGlnaXRzID0gMikNCg0KY2F0KCJQcm9iYWJpbGl0eSB0aGF0IHRoZSB0ZWFtIGxlYWRpbmcgYXQgaGFsZiB0aW1lIHdpbnMgdGhlIGVudGlyZSBnYW1lOiAiLCBodF9mdF93aW5fcHJvYiwgIiUiKQ0KYGBgDQoNCmBgYHtyfQ0KZmlnIDwtIHBsb3RfbHkoDQogIHkgPSBjKCJIb21lIHdpbnMgYWZ0ZXIgbGVhZGluZyBhdCBIVCIsICJBd2F5IHdpbnMgYWZ0ZXIgbGVhZGluZyBhdCBIVCIsICJEcmF3IGF0IEZUICYgSFQiKSwgDQogIHggPSBjKGhvbWVfd2luX3Byb2IsIGF3YXlfd2luX3Byb2IsIGRyYXdfcHJvYiksDQogIHR5cGUgPSAiYmFyIg0KKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQodGl0bGUgPSAiR2FtZSBQcm9ncmVzcyBPdmVydmlldyIsDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiUHJvYmFiaWxpdHkiKSkNCg0KZmlnDQoNCmBgYA0KIyMjIEZyYWdlc3RlbGx1bmcgMjoNCiMjIyBEYXMgSGVpbXRlYW0gc2NoaWVzc3QgbWVociBhdWZzIFRvciBhbHMgZGFzIEF1c3fDpHJ0c3RlYW0sIGFiZXIgd2VsY2hlcyBUZWFtIGlzdCBlZmZpemllbnRlcj8NCg0KYGBge3J9DQojIFBsb3QgRnVsbHRpbWUgSG9tZSBTaG90cyB2cyBIb21lIEdvYWxzIA0KcDEgPC0gZGYgJT4lDQogIHBsb3RfbHkoeCA9IH5GVEhHLCB5ID0gfkhTLCBjb2xvcmF4aXMgPSAnY29sb3JheGlzJykgJT4lDQogIGFkZF9oaXN0b2dyYW0yZChuYmluc3kgPSA0MCkNCg0KIyBQbG90IEZ1bGx0aW1lIEF3YXkgU2hvdHMgdnMgQXdheSBHb2FscyANCnAyIDwtIGRmICU+JQ0KICBwbG90X2x5KHggPSB+RlRBRywgeSA9IH5BUywgY29sb3JheGlzID0gJ2NvbG9yYXhpcycpICU+JQ0KICBhZGRfaGlzdG9ncmFtMmQobmJpbnN5ID0gNDApDQoNCiMgQWRkIGJvdGggcGxvdHMgdG9nZXRoZXIgdG8gYnVpbGQgc3VicGxvdA0Kc3VicGxvdChwMSwgcDIsIG5yb3dzID0gMSwgc2hhcmVYID0gRkFMU0UsIHNoYXJlWSA9IEZBTFNFKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkdvYWxzIHZzIFNob3RzIE92ZXJ2aWV3IiwNCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiSG9tZSBHb2FscyIpLA0KICAgIHhheGlzMiA9IGxpc3QodGl0bGUgPSAiQXdheSBHb2FscyIpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJIb21lIFNob3RzIiksDQogICAgeWF4aXMyID0gbGlzdCh0aXRsZSA9ICJBd2F5IFNob3RzIiksDQogICAgY29sb3JheGlzPWxpc3QoY29sb3JzY2FsZT0nSmV0JykNCiAgKQ0KYGBgDQpBbmhhbmQgZGVzIFBsb3RzIG9iZW4gaXN0IGd1dCB6dSBzZWhlbiwgZGFzcyBkYXMgSGVpbXRlYW0gZWhlciAxLTIgVG9yZSBzY2hpZXNzdCB1bmQgOS0xNiBUb3JzY2jDvHNzZSBhdWZ3ZWlzdC4gQmVpbSBBdXN3w6RydHN0ZWFtIHNpZWh0cyBldHdhcyBhbmRlcnMgYXVzOyBTaWUgc2NoaWVzc2VuIGVoZXIgMC0xIFRvciB1bmQgd2Vpc2VuIDYtMTEgVG9yc2Now7xzc2UgYXVmLg0KDQpgYGB7cn0NCiMgRml0IHRoZSByZWdyZXNzaW9uIG1vZGVsIG9mIEZ1bGx0aW1lIEF3YXkgR29hbHMgb24gQXdheSBTaG90cw0KbSA8LSBsbShGVEFHIH4gQVMsIGRhdGEgPSBkZikNCg0KIyBDcmVhdGUgdGhlIHNjYXR0ZXJwbG90IHdpdGggc21vb3RoZXINCmRmICU+JQ0KICBwbG90X2x5KHggPSB+QVMsIHkgPSB+RlRBRykgJT4lDQogIGFkZF9tYXJrZXJzKHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lDQogIGFkZF9saW5lcyh5ID0gfmZpdHRlZChtKSkNCmBgYA0KYGBge3J9DQpkZiAlPiUNCiAgcGxvdF9seSh4ID0gfkhTLCB5ID0gfkFTLCBjb2xvcmF4aXMgPSAnY29sb3JheGlzJykgJT4lDQogIGFkZF9oaXN0b2dyYW0yZChuYmluc3ggPSA3MCwgbmJpbnN5ID0gNjApICU+JQ0KICBsYXlvdXQoY29sb3JheGlzPWxpc3QoY29sb3JzY2FsZT0nSmV0JykpDQpgYGANCg0KYGBge3J9DQpkZl9lZmZpY2llbmN5IDwtIGRmICU+JQ0KICBzdW1tYXJpc2UoDQogICAgIkhvbWUgR29hbHMgcGVyIFNob3QiID0gcm91bmQoc3VtKEZUSEcpIC8gc3VtKEhTKSxkaWdpdHMgPSAzKSwNCiAgICAiSG9tZSBHb2FscyBwZXIgU2hvdCBvbiBUYXJnZXQiID0gcm91bmQoc3VtKEZUSEcpIC8gc3VtKEhTVCksZGlnaXRzID0gMyksDQogICAgIkF3YXkgR29hbHMgcGVyIFNob3QiID0gcm91bmQoc3VtKEZUQUcpIC8gc3VtKEFTKSxkaWdpdHMgPSAzKSwNCiAgICAiQXdheSBHb2FscyBwZXIgU2hvdCBvbiBUYXJnZXQiID0gcm91bmQoc3VtKEZUQUcpIC8gc3VtKEFTVCksZGlnaXRzID0gMykNCikNCiMgVHJhbnNwb3NlIGRhdGFmcmFtZQ0KdF9kZl9lZmZpY2llbmN5IDwtIGRhdGEuZnJhbWUoIlBlcmNlbnQiID0gdChkZl9lZmZpY2llbmN5KSkNCmBgYA0KDQpgYGB7cn0NCmZpZyA8LSBwbG90X2x5KA0KICB5ID0gYygiSG9tZSBHb2FscyBwZXIgU2hvdCIsICJIb21lIEdvYWxzIHBlciBTaG90IG9uIFRhcmdldCIsICJBd2F5IEdvYWxzIHBlciBTaG90IiwgIkF3YXkgR29hbHMgcGVyIFNob3Qgb24gVGFyZ2V0IiksDQogIHggPSB0X2RmX2VmZmljaWVuY3kkUGVyY2VudCwNCiAgdHlwZSA9ICJiYXIiDQopDQoNCmZpZyA8LSBmaWcgJT4lIGxheW91dCh0aXRsZSA9ICJUZWFtIEVmZmljaWVuY3kiLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5IikpDQpmaWcNCmBgYA0KDQoNCg==